package firbi.base.com;

import com.google.android.maps.GeoPoint;

import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import junit.framework.TestCase;

public class FirbiCom_Unit_Test extends TestCase {

	protected void setUp() {
	}
	
	/**
	 * This method runs the appropriate test when called with a test name.
	 * 
	 * @param testName	The name of the test to run
	 */
	protected void runTest(String testName) {
		Log.i("test", "running test:"+testName);
		if(testName.equalsIgnoreCase("testGeoPointConversion"))
			testGeoPointConversions();
		if(testName.equalsIgnoreCase("testGetRoutes"))
			testGetRoutes();
		if(testName.equalsIgnoreCase("testGetStops"))
			testGetStops();
	}
	
	protected void tearDown() {
		
	}
	
	/**
	 * This test tests that the methods of FirbiCom involving GeoPoint conversion work correctly. The test has
	 * two arrays micropoints and latlons that can be changed to try different sets of data on the general tests.
	 * When changing the arrays to add test data make sure that each number you add has it's corresponding conversion
	 * in the same position in the other array. The micropoints array are the GeoPoint ints and latlons are the doubles
	 * that are the converted values of the ints in the micropoints array. The conversion is micropoints[i][x] should equal
	 * (10^6) * latlons[i][x], be sure to maintain this relationship when adding more test values to the array.
	 */
	@SmallTest
	public void testGeoPointConversions() {
		int[][] micropoints = {	{47668393, 		-122290363},
								{10000000,		20000000},
								{1,				2}};
		
		double[][] latlons = {	{47.668393, 	-122.290363},
								{10.000000,		20.000000},
								{0.000001,	0.000002}};
		
		for(int i = 0; i < micropoints.length; i++){
			double gTOd_lat = FirbiCom.geoIntToDouble(micropoints[i][0]);
			double gTOd_lon = FirbiCom.geoIntToDouble(micropoints[i][1]);
			
			assertEquals("FirbiCom.geoIntToDouble failed!", latlons[i][0], gTOd_lat);
			assertEquals("FirbiCom.geoIntToDouble failed!", latlons[i][1], gTOd_lon);
			
			int dTOg_lat = FirbiCom.doubleToGeoInt(latlons[i][0]);
			int dTOg_lon = FirbiCom.doubleToGeoInt(latlons[i][1]);
			
			assertEquals("FirbiCom.doubleToGeoInt failed!", micropoints[i][0], dTOg_lat);
			assertEquals("FirbiCom.doubleToGeoInt failed!", micropoints[i][1], dTOg_lon);
			
			GeoPoint test = new GeoPoint(micropoints[i][0], micropoints[i][1]);
			double[] dpoint = FirbiCom.geoPointToDoubles(test);
			
			assertEquals("FirbiCom.geoPointToDoubles failed!", latlons[i][0], dpoint[0]);
			assertEquals("FirbiCom.geoPointToDoubles failed!", latlons[i][1], dpoint[1]);
		}
		
		assertNull("FirbiCom.geoPointToDoubles did not return null when passed null!", FirbiCom.geoPointToDoubles(null));
	}
	
	/**
	 * This test tests all the methods of FirbiCom which get routes or in other terms return BusRoutes. This
	 * method similar to most of the tests in the suite has an array of values to test. Adding test cases should
	 * be as easy as adding another array to the 2d testqueries array, but make sure to follow the format specified
	 * in the comment above the array. This method will run once for each test case in testqueries and will test
	 * all of the methods that return BusRoutes by making sure that all the values returned from all the different
	 * methods have the relationships they should have. For example, if you get a route by id and then get another by
	 * the same routes routeNumber then you should get the same route back. These kinds of truths are tested as well
	 * as individual qualities of the routes that are returned.
	 */
	@MediumTest
	public void testGetRoutes() {
		GeoPoint seattle = new GeoPoint(47668393, -122290363);
									//routeNumber	id				location
		Object[][] testqueries = {	{"71",			"0001_71",		seattle},
									{"30",			"0001_30",		seattle},
									{"67",			"0001_67",		seattle}};
		
		for(int i = 0; i < testqueries.length; i++){
			String routeNumber = ((String)testqueries[i][0]);
			String id = ((String)testqueries[i][1]);
			GeoPoint location = ((GeoPoint)testqueries[i][2]);
			
			BusRoute result = FirbiCom.getRoute(id);
			assertNotNull("getRoute("+id+") returned null but the passed id is known to be valid!", result);
			assertEquals("getRoute("+id+") returned a BusRoute with incorrect id!", id, result.getId());
			assertEquals("getRoute("+id+") retruned a BusRoute with incorrect routeNumber!", routeNumber, result.getRouteNumber());
			
			BusRoute[] result2 = FirbiCom.getRoutes(routeNumber, location);
			
			assertNotNull("getRoute("+routeNumber+", "+seattle.toString()+") got null for a known non null route and location!", result2);
			assertTrue("getRoute("+routeNumber+", "+seattle.toString()+") got no BusStops for a route which is known to have BusStops!", result2.length>0);
			
			BusRoute result3 = FirbiCom.getRoute(result2[0].getId());
			assertNotNull("getRoute("+result2[0].getId()+") returned null but that id is known to have a corresponding BusRoute!", result3);
			
			boolean found = false;
			for(int j = 0; j < result2.length; j++){
				BusRoute check = result2[j];
				if(check.equals(result))
					found = true;
				assertNotNull("getRoute("+routeNumber+", "+seattle.toString()+") recieved an array of BusRoutes with null in it! at position "+j, check);
				assertTrue("getRoute("+routeNumber+", "+seattle.toString()+") recieved an array of BusRoutes with one BusRoute whos routeNumber was not similar to what was passed in!", check.getRouteNumber().contains(routeNumber));
			}
			assertTrue("getRoute("+routeNumber+", "+seattle.toString()+") returned a BusRoute array that did not contain the BusRoute found by getRoute("+id+")!", found);
		}
		
	}
	
	/**
	 * This test tests all of the methods that get stops or in other words that return BusStops. This method
	 * uses the different methods to make sure that each is returning the correct values by checking relationships
	 * that should  be true between the results of different methods. For example, if you get a stop x by id and
	 * then get stop y by x.stopNumber with the same location as x x and y should be the same. These relationships are
	 * tested as well as individual properties of the stops returned. Test cases can be added similarly as other test methods
	 * in this class you add an array to the testqueries array with values that fit the specified format in the comment above
	 * testqueries.
	 */
	@MediumTest
	public void testGetStops() {
									//id				stopNumber		location/near							radius
		Object[][] testqueries = {	{"0001_10020", 		"10020", 		new GeoPoint(47668393, -122290363), 	400},
									{"0001_110", 		"110", 			new GeoPoint(47599781, -122329571), 	400}};
		
		for(int i = 0; i < testqueries.length; i++){
			String id = ((String)testqueries[i][0]);
			String stopNumber = ((String)testqueries[i][1]);
			GeoPoint location = ((GeoPoint)testqueries[i][2]);
			Integer radius = ((Integer)testqueries[i][3]);
			
			//getStop(String id)
			BusStop stop = FirbiCom.getStop(id);
			assertNotNull("getStop("+id+") returned null but id is known to be valid id!", stop);
			assertEquals("", id, stop.getId());
			assertEquals("", stopNumber, stop.getStopNumber());
			
			//Test getStops(GeoPoint center, int radius)
			BusStop[] stops1 = FirbiCom.getStops(location, radius);
			assertNotNull("getStops("+location.toString()+", "+radius+") returned null but stops are known to be within the radius of the location passed!", stops1);
			boolean found = false;
			for(int j = 0; j < stops1.length; j++){
				BusStop check = stops1[j];
				if(check==stop)
					found = true;
				assertNotNull("getStops("+location+", "+radius+") returned a BusStop array with null inside!", check);
			}
			assertTrue("getStops("+location.toString()+", "+radius+") did not return a BusStop known to be in the array specified!", found);
			
			//Test getStops(String stopNumber, GeoPoint near)
			BusStop[] stops2 = FirbiCom.getStops(stopNumber, location);
			assertNotNull("getStops("+stopNumber+", "+location.toString()+") returned null but there are known stops near the location passed with the stopNumber passed!", stops1);
			found = false;
			for(int j = 0; j < stops2.length; j++){
				BusStop check = stops2[j];
				if(check == stop)
					found = true;
				assertNotNull("getStops("+stopNumber+", "+location.toString()+") returned a BusStop array with null inside!", check);
				assertEquals("getStops("+stopNumber+", "+location.toString()+") returned a BusStop that had the wrong stopNumber!", stopNumber, check.getStopNumber());
			}
			assertTrue("getStops("+stopNumber+", "+location.toString()+") did not return a BusStop known to have the routeNumber and location passed!", found);
		}
		
	}
	
}
